#!/opt/py3.6/ve1/bin/python
import os
import sys
import json
PY2 = sys.version_info[0] == 2
if not PY2:
    string_types = (str,)
else:
    string_types = (str, unicode)
from ast import literal_eval
from werkzeug.wrappers import Request, Response
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, NotFound
from werkzeug.wsgi import SharedDataMiddleware
from werkzeug.wsgi import wrap_file
from werkzeug.datastructures import Headers
from werkzeug.serving import run_simple

def get_env_var(var, dval):
    return (os.environ[var] if (var in os.environ) else dval)

def get_es_hosts(req):
    es_host = get_env_var('ZS_ELK','localhost')
    if req is not None and 'es_host' in req:
        es_host = req['es_host']
    #  ES_ELK="192.168.10.20:3200,localhost,es_cluster:8200"
    #  default port: 9200
    return es_host.split(',')

def get_redis_off(req):
    redis_off = get_env_var('REDIS_OFF','True')
    if req is not None and 'redis_off' in req:
        redis_off = req['redis_off']
    return redis_off

def get_redis_off(req):
    redis_off = get_env_var('REDIS_OFF','True')
    if req is not None and 'redis_off' in req:
        redis_off = req['redis_off']
    return redis_off

def get_redis_host(req):
    redis_par = get_env_var('ZS_REDIS', 'localhost:6379')
    if req is not None and 'redis_host' in req:
        redis_par = req['redis_host']
    #  ES_REDIS="192.168.10.20:5800"
    #  default port: 6379
    if len(redis_par.split(':')) == 1:
        return [redis_par, 6379]
    elif len(redis_par.split(':')) == 2:
        return redis_par.split(':') 
    else:
        raise Exception("Can not resolve redis_host parameter in request.")

def _endpoint_from_view_func(view_func):
    assert view_func is not None, 'expected view func if endpoint is not provided.'
    return view_func.__name__

def send_file(filename):
    if isinstance(filename, string_types):
        if not os.path.isabs(filename):
            filename = os.path.join(os.environ['PWD'], filename)
    else:
        raise Exception('filename should be a string.')
    headers = Headers()
    file = open(filename, 'rb')
    fsize = os.path.getsize(filename)
    headers['Content-Length'] = fsize
    #attachment_filename = os.path.basename(filename)
    #headers['Content-Disposition'] = "attachment, filename='%s'" % attachment_filename
    attachment_filename = {"filename": os.path.basename(filename)}
    headers.add('Content-Disposition', 'attachment', **attachment_filename )
    #data = wrap_file(request.environ, file)
    return Response(file, headers=headers, direct_passthrough=True)

class Application(object):
    def __init__(self):
        self.view_functions = {}
        self.url_map = Map()

    def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
        if endpoint is None:
            endpoint = _endpoint_from_view_func(view_func)
        options['endpoint'] = endpoint
        methods = options.pop('methods', None)

        if methods is None:
            methods = getattr(view_func, 'methods', None) or ('GET',)
        if isinstance(methods, string_types):
            raise TypeError('Allowed methods have to be iterables of strings, '
                            'for example: @app.route(..., methods=["POST"])')
        methods = set(item.upper() for item in methods)

        rule = Rule(rule, methods=methods, **options)
        self.url_map.add(rule)
        if view_func is not None:
            old_func = self.view_functions.get(endpoint)
            if old_func is not None and old_func != view_func:
                raise AssertionError('View function mapping is overwriting an '
                                     'existing endpoint function: %s' % endpoint)
            self.view_functions[endpoint] = view_func

    def route(self, rule, **options):
        def decorator(f):
            endpoint = options.pop('endpoint', None)
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator

    def dispatch_request(self, request):
        adapter = self.url_map.bind_to_environ(request.environ)
        try:
            endpoint, values = adapter.match()
            if request.method != 'POST':
                return self.view_functions[endpoint](**request.args.to_dict())
            else:
                #print(json.loads(request.data))
                return self.view_functions[endpoint](**json.loads(request.data))
        except HTTPException as e:
            return e

    def __call__(self, environ, start_response):
        request = Request(environ)
        response = self.dispatch_request(request)
        if not isinstance(response, (Response, HTTPException)):
            response = Response(response, status=200)
        return response(environ, start_response)

if __name__ == "__main__":
    print(os.environ['PWD'])
    app = Application()

    @app.route('/test')
    def test(**kwargs):
        msg = "Recvied args: "
        for k,v in kwargs.items():
            if k != "request":
                msg += "%s: %s," % (k,v)
        return msg

    run_simple('0.0.0.0', 9002, app, use_debugger=True, use_reloader=True)


